package com.duojuhe.common.user.service.impl;

import com.duojuhe.cache.LoginUserTokenCache;
import com.duojuhe.cache.SystemDictCache;
import com.duojuhe.common.enums.IdResourceEnum;
import com.duojuhe.common.file.service.FileUploadHandler;
import com.duojuhe.common.utils.file.UploadFileBean;
import com.duojuhe.coremodule.system.entity.SystemDict;
import com.duojuhe.common.bean.SystemMenuInfoVo;
import com.duojuhe.common.user.dto.UserAuthorizationVo;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.config.FileUploadConfig;
import com.duojuhe.common.enums.user.UserEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.user.dto.loginuser.ChangeLoginUserInfoReq;
import com.duojuhe.common.user.dto.loginuser.ChangeLoginUserPasswordReq;
import com.duojuhe.common.user.dto.loginuser.QueryLoginUserInfoRes;
import com.duojuhe.common.user.service.CurrentLoginUserService;
import com.duojuhe.common.utils.encryption.md5.MD5Util;
import com.duojuhe.common.utils.file.UploadFileUtil;
import com.duojuhe.common.utils.tree.TreeBaseBean;
import com.duojuhe.common.utils.tree.TreeUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.system.entity.SystemRole;
import com.duojuhe.coremodule.system.entity.SystemUser;
import com.duojuhe.coremodule.system.mapper.SystemRoleMapper;
import com.duojuhe.coremodule.system.mapper.SystemUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CurrentLoginUserServiceImpl  extends BaseService implements CurrentLoginUserService {
    @Resource
    private FileUploadConfig fileUploadConfig;
    @Resource
    private SystemDictCache systemDictCache;
    @Resource
    private LoginUserTokenCache loginUserTokenCache;
    @Resource
    private FileUploadHandler fileUploadHandler;
    @Resource
    private SystemUserMapper systemUserMapper;
    @Resource
    private SystemRoleMapper systemRoleMapper;
    /**
     * 【获取当前用户菜单权限】【tree型结构】获取当前登录用户的权限菜单
     * @return
     */
    @Override
    public ServiceResult<List<SystemMenuInfoVo>> queryCurrentLoginUserMenuTree() {
        List<SystemMenuInfoVo> menuList = getCurrentLoginUserInfoDTO().getMenuInfoVOList();
        if (menuList==null){
            return ServiceResult.ok(new ArrayList<>());
        }
        List<TreeBaseBean> tList = TreeUtil.treeList(menuList);
        return ServiceResult.ok(tList);
    }


    /**
     * 【获取当前用户权限】获取当前用户拥有的权限
     * @return
     */
    @Override
    public ServiceResult<UserAuthorizationVo> queryCurrentLoginUserAuthorization() {
        List<SystemMenuInfoVo> menuList = getCurrentLoginUserInfoDTO().getMenuInfoVOList();
        UserAuthorizationVo userAuthorizationVo = new UserAuthorizationVo();
        if (menuList!=null){
            List<String> menuCodeList = menuList.stream().map(SystemMenuInfoVo::getMenuCode).collect(Collectors.toList());
            userAuthorizationVo.setPermissionsList(menuCodeList);
        }
        return ServiceResult.ok(userAuthorizationVo);
    }

    /**
     *【修改当前用户密码】修改当前登录用户的密码
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult changeCurrentLoginUserPassword(ChangeLoginUserPasswordReq req) {
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //检查当前登录用户是否存在
        SystemUser systemUserOld = checkCurrentLoginUserIsExist(userTokenInfoVo);
        //旧密码
        String oldPwd = MD5Util.getMD532(MD5Util.getMD532(req.getOldPassword()));
        if (!oldPwd.equals(systemUserOld.getPassword())) {
            throw new DuoJuHeException(ErrorCodes.USER_OLD_PASSWORD_ERROR);
        }
        //新密码
        String newPwd = MD5Util.getMD532(MD5Util.getMD532(req.getPassword()));
        //新密码不可与旧密码相同
        if (newPwd.equals(oldPwd)) {
            throw new DuoJuHeException(ErrorCodes.USER_NEW_OLD_PASSWORD_ERROR);
        }
        //用户id
        String userId = systemUserOld.getUserId();
        //更新用户对象构建
        SystemUser systemUser = new SystemUser();
        systemUser.setUserId(userId);
        systemUser.setPassword(newPwd);
        systemUserMapper.updateByPrimaryKeySelective(systemUser);
        //密码修改了，强制踢出刚用户的所有在线会话
        loginUserTokenCache.kickOutOnlineUserByUserId(userId);
        return ServiceResult.ok(ErrorCodes.UPDATE_SUCCESS_AGAIN_LOGIN.getMessage(),userId);
    }

    /**
     *【修改当前用户头像】修改当前登录用户的头像
     * @param file
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult<String> changeCurrentLoginUserHeadPortrait(MultipartFile file) {
        if (file==null||file.isEmpty()){
            throw new DuoJuHeException(ErrorCodes.UPLOAD_FILE_NOT_FOUND);
        }
        // 判断文件大小
        long fileSize = file.getSize();
        long maxImageSize = fileUploadConfig.getMaxSize(fileUploadConfig.getMaxImageSize());
        if (fileSize > maxImageSize) {
            throw new DuoJuHeException(ErrorCodes.UPLOAD_FILE_TOO_LARGE);
        }
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //查询用户是否存在
        SystemUser systemUserOld = systemUserMapper.selectByPrimaryKey(userTokenInfoVo.getUserId());
        if (systemUserOld == null) {
            throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
        }
        //允许图片文件类型
        String[] allowFiles = fileUploadConfig.getImageAllowFiles();
        //用户目录
        String userDir = userTokenInfoVo.getTenantNumber()+File.separator+userTokenInfoVo.getUserNumber();
        //用户头像目录dir
        String userHeaderDir = File.separator+"headPortrait"+File.separator+userDir;
        //文件根目录
        String rootPath = fileUploadConfig.getRootPath()+userHeaderDir;
        //文件前缀
        String imageUrlPrefix = fileUploadConfig.getFileUrlPrefix()+userHeaderDir;
        //附件上传前缀域名
        String filePrefixDomain = fileUploadConfig.getFilePrefixDomain();
        //请求路径
        UploadFileBean uploadFileBean = UploadFileUtil.writeSingleImageToDisk(file,allowFiles,filePrefixDomain, rootPath, imageUrlPrefix);
        //请求路径
        String fileAbsolutePath = uploadFileBean.getFileAbsolutePath();
        if (StringUtils.isBlank(fileAbsolutePath)) {
            throw new DuoJuHeException(ErrorCodes.UPLOAD_FILE_FORMAT_ERROR);
        }
        //保存文件到文件库
        String relationId = systemUserOld.getUserId();
        //关联id来源
        String relationIdSource = IdResourceEnum.IdResource.system_user.getKey();
        fileUploadHandler.addRelationNewFileUpload(relationId,relationIdSource,uploadFileBean,userTokenInfoVo);
        //用户对象
        SystemUser systemUser = new SystemUser();
        systemUser.setUserId(systemUserOld.getUserId());
        systemUser.setHeadPortrait(fileAbsolutePath);
        systemUserMapper.updateByPrimaryKeySelective(systemUser);
        //用户头像发生了变化，需要重新登录
        loginUserTokenCache.kickOutOnlineUserByUserId(systemUserOld.getUserId());
        return ServiceResult.ok(ErrorCodes.UPDATE_SUCCESS_AGAIN_LOGIN.getMessage(),fileAbsolutePath);
    }

    /**
     *【修改当前用户基本信息】修改当前登录用户的基本信息
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult changeCurrentLoginUserInfo(ChangeLoginUserInfoReq req) {
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //检查当前登录用户是否存在
        SystemUser systemUserOld = checkCurrentLoginUserIsExist(userTokenInfoVo);
        //获取新手机号码 并检查新手机号码是否被使用了
        String mobileNumber = req.getMobileNumber();
        if (!mobileNumber.equals(systemUserOld.getMobileNumber())){
            isExistUserMobileNumber(mobileNumber);
        }
        SystemUser systemUser = new SystemUser();
        systemUser.setUserId(systemUserOld.getUserId());
        systemUser.setRealName(req.getRealName());
        systemUser.setMobileNumber(mobileNumber);
        systemUser.setMotto(req.getMotto());
        systemUser.setGenderCode(req.getGenderCode());
        systemUserMapper.updateByPrimaryKeySelective(systemUser);
        //用户基本信息修改了，强制踢出刚用户的所有在线会话
        loginUserTokenCache.kickOutOnlineUserByUserId(systemUserOld.getUserId());
        return ServiceResult.ok(ErrorCodes.UPDATE_SUCCESS_AGAIN_LOGIN.getMessage(),systemUserOld.getUserId());
    }

    /**
     *【获取当前登录用户基本信息】获取当前登录用户基本信息
     * @return
     */
    @Override
    public ServiceResult<QueryLoginUserInfoRes> queryCurrentLoginUserInfoRes() {
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //检查当前登录用户是否存在
        SystemUser systemUser = checkCurrentLoginUserIsExist(userTokenInfoVo);
        //性别
        String genderCode = systemUser.getGenderCode();
        //缓存中取出数据字典对应值
        SystemDict gender = systemDictCache.getSystemDictByDictCode(genderCode);
        //查询角色
        SystemRole systemRole = systemRoleMapper.selectByPrimaryKey(systemUser.getRoleId());
        QueryLoginUserInfoRes res = new QueryLoginUserInfoRes();
        res.setLoginName(systemUser.getLoginName());
        res.setRealName(systemUser.getRealName());
        res.setHeadPortrait(systemUser.getHeadPortrait());
        res.setMobileNumber(systemUser.getMobileNumber());
        res.setRoleName(systemRole!=null?systemRole.getRoleName():"");
        res.setUserTypeCode(systemUser.getUserTypeCode());
        res.setUserTypeName(UserEnum.USER_TYPE.getValueByKey(systemUser.getUserTypeCode()));
        res.setCreateTime(systemUser.getCreateTime());
        res.setUserId(systemUser.getUserId());
        res.setMotto(systemUser.getMotto());
        res.setGenderCode(genderCode);
        res.setGenderName(gender.getDictName());
        res.setTenantName(userTokenInfoVo.getTenantName());
        res.setTenantAbbreviation(userTokenInfoVo.getTenantAbbreviation());
        return ServiceResult.ok(res);
    }

    /**
     * 用户注销登录
     * @return
     */
    @Override
    public ServiceResult currentLoginUserLogout() {
        UserTokenInfoVo adminUserInfoDTO = getCurrentLoginUserInfoDTO();
        loginUserTokenCache.delUserTokenInfoVoCacheByToken(adminUserInfoDTO.getToken());
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 检查当前登录用户是否存在
     * @return
     */
    private SystemUser checkCurrentLoginUserIsExist(UserTokenInfoVo userTokenInfoVo){
        SystemUser systemUser = systemUserMapper.selectByPrimaryKey(userTokenInfoVo.getUserId());
        if (systemUser == null) {
            throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
        }
        return systemUser;
    }

    /**
     * 判断手机号码是否存在
     */
    private void isExistUserMobileNumber(String mobileNumber) {
        if (StringUtils.isBlank(mobileNumber)){
            throw new DuoJuHeException(ErrorCodes.MOBILE_NUMBER_EXIST);
        }
        SystemUser systemUser = systemUserMapper.querySystemUserByMobileNumber(mobileNumber);
        if (systemUser != null) {
            throw new DuoJuHeException(ErrorCodes.MOBILE_NUMBER_EXIST);
        }
    }
}
